package so.sao.code.service.service.impl;

import static so.sao.code.service.infrastructure.EventsPublisher.publish;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import so.sao.code.dto.request.TagBatchCreate;
import so.sao.code.dto.request.TerminalDownloadRequest;
import so.sao.code.dto.response.AvailableNum;
import so.sao.code.dto.response.TagAvailableTypeDto;
import so.sao.code.dto.response.TagBatchPrintFileDto;
import so.sao.code.dto.response.TerminalDownloadResponse;
import so.sao.code.service.config.CloudContainerConfig;
import so.sao.code.service.domain.entity.EnterpriseInfo;
import so.sao.code.service.domain.entity.LookupTable;
import so.sao.code.service.domain.entity.RangeActivation;
import so.sao.code.service.domain.entity.TagBatch;
import so.sao.code.service.domain.entity.TagBatchConfig;
import so.sao.code.service.domain.entity.TagBatchLookupTable;
import so.sao.code.service.domain.entity.TagScrap;
import so.sao.code.service.domain.entity.TerminalDownloadRecord;
import so.sao.code.service.domain.event.TagBatchCreateEvent;
import so.sao.code.service.domain.event.TagBatchDownloadEvent;
import so.sao.code.service.domain.service.TagBatchDomainService;
import so.sao.code.service.infrastructure.SessionContext;
import so.sao.code.service.infrastructure.dozer.Mapper;
import so.sao.code.service.infrastructure.enums.ActivationMethod;
import so.sao.code.service.infrastructure.enums.CodeMessage;
import so.sao.code.service.infrastructure.enums.OPERATION;
import so.sao.code.service.infrastructure.enums.PrintFileDownloadMethod;
import so.sao.code.service.infrastructure.enums.PrintFileFormatStatus;
import so.sao.code.service.infrastructure.enums.PrintFileStatus;
import so.sao.code.service.infrastructure.enums.ProductionRegister;
import so.sao.code.service.infrastructure.enums.SEQ_TYPE;
import so.sao.code.service.infrastructure.enums.TAG_BATCH_TYPE;
import so.sao.code.service.infrastructure.enums.TagBatchType;
import so.sao.code.service.infrastructure.enums.TagRangeStatus;
import so.sao.code.service.infrastructure.model.vo.RangeActivationVO;
import so.sao.code.service.infrastructure.model.vo.TagBatchPrintFormatVO;
import so.sao.code.service.infrastructure.model.vo.TagBatchVO;
import so.sao.code.service.infrastructure.model.vo.TagMetaVO;
import so.sao.code.service.infrastructure.utils.MD5Utils;
import so.sao.code.service.repository.EnterpriseInfoDao;
import so.sao.code.service.repository.RangeActivationDao;
import so.sao.code.service.repository.TagBatchConfigDao;
import so.sao.code.service.repository.TagBatchDao;
import so.sao.code.service.repository.TagBatchDownloadLogDao;
import so.sao.code.service.repository.TagBatchLookupTableDao;
import so.sao.code.service.repository.TagScrapDao;
import so.sao.code.service.repository.TerminalDownloadResultDao;
import so.sao.code.service.service.LookupTableService;
import so.sao.code.service.service.TagBatchLookupTableService;
import so.sao.code.service.service.TagBatchService;
import so.sao.data.dto.response.EnterpriseDTO;
import so.sao.data.dto.response.FactoryDTO;
import so.sao.data.dto.response.IndustrialComputerDTO;
import so.sao.data.feign.client.EnterpriseClient;
import so.sao.data.feign.client.FactoryClient;
import so.sao.data.feign.client.IndustrialComputerClient;
import so.sao.ffw.dto.request.TagBatchSequenceInfo;
import so.sao.ffw.dto.request.TagBatchStatusRequest;
import so.sao.ffw.dto.response.TagBatchStatusResponse;
import so.sao.ffw.feign.client.TagBatchReportClient;
import so.sao.file.datastore.exception.FileDatastoreException;
import so.sao.file.datastore.service.FileService;
import so.sao.nosql.datastore.enums.tag.TagStatus;
import so.sao.sso.common.CommonConstants;
import so.sao.top.core.util.CipherZipUtil;
import so.sao.top.core.util.exceptions.ServiceException;
import so.sao.top.core.util.mapper.JsonMapper;
import so.sao.top.core.util.rest.RestException;

@Service
public class TagBatchServiceImpl implements TagBatchService {
	private static Logger logger = LoggerFactory.getLogger(TagBatchServiceImpl.class);
	@Autowired
	TagBatchDao tagBatchDao;

	@Autowired
	LookupTableService lookupTableService;
	@Autowired
	FileService fileService;

	@Autowired
	CloudContainerConfig cloudContainerConfig;
	@Autowired
	TagScrapDao tagScrapDao;
	@Autowired
	RangeActivationDao rangeActivationDao;
	@Autowired
	TerminalDownloadResultDao terminalDownloadResultDao;
	@Autowired
	TagBatchLookupTableDao tagBatchLookupTableDao;
	@Autowired
	TagBatchReportClient tagBatchReportClient;

	@Autowired
	EnterpriseClient enterpriseClient;

	@Autowired
	EnterpriseInfoDao enterpriseInfoDao;

	@Autowired
	TagBatchDomainService tagBatchDomainService;
	@Autowired
	TagBatchDownloadLogDao tagBatchDownloadLogDao;
	@Autowired
	SessionContext context;
	@Autowired
	TagBatchConfigDao tagBatchConfigDao;
	@Autowired
	IndustrialComputerClient industrialComputerClient;
	@Autowired
	FactoryClient factoryClient;
	@Autowired
	TagBatchLookupTableService tagBatchLookupTableService;
	@Autowired
	protected JsonMapper jsonMapper;
	@Value("${sao.code.tempBackFilePath}")
	private String tempBackFilePath;

	@Override
	@Transactional
	public List<Long> create(TagBatchCreate tagBatchCreate) {
		if (!context.CURRECT_USER.getEseId().equals(1L)
				&& !tagBatchCreate.getEseId().equals(context.CURRECT_USER.getEseId())) {
			throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest);
		}
		TagBatch tagBatch = Mapper.map(tagBatchCreate, TagBatch.class).become();
		EnterpriseInfo enterpriseInfo = Optional.ofNullable(enterpriseInfoDao.findByEseId(tagBatch.getEseId()))
				.orElseThrow(() -> new RestException(HttpStatus.BAD_REQUEST, "无权限完成此操作，请联系管理员"));
		Long totalTagCount = tagBatch.getTagCount();
		LookupTable lookupTable = Optional
				.ofNullable(lookupTableService.findAvailableRange(totalTagCount,
						SEQ_TYPE.fromValue(tagBatchCreate.getSeqType())))
				.orElseThrow(() -> new RestException(HttpStatus.NOT_ACCEPTABLE, CodeMessage.NOAvailableRange,
						enterpriseInfo.getSubDomain(), totalTagCount));
		Long createdCount = Optional.ofNullable(tagBatchDao.sumTagCountByEseId(tagBatch.getEseId())).orElse(0L);
		if (!context.CURRECT_USER.getEseId().equals(1L) && totalTagCount > enterpriseInfo.getUpCount()) {
			throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.OverLimitCount, createdCount, totalTagCount,
					enterpriseInfo.getUpCount());
		}
		// tagBatch.setMasterEseId(enterprise.getId());
		tagBatch.setSubDomain(enterpriseInfo.getSubDomain());
		tagBatch.setLookupId(lookupTable.getId());
		tagBatch.setSeqnumStart(lookupTable.getSeqnumStart() + lookupTable.getCurrentCount());
		tagBatch.setSeqnumEnd(tagBatch.getSeqnumStart() + tagBatch.getTagCount() - 1);
		tagBatchDomainService.checkDomainLength(tagBatch.getCodeLength(), tagBatch.getSeqnumEnd(), tagBatch.getDomain(),
				enterpriseInfo.getSubDomain());
		List<TagBatch> result = tagBatchDao.save(tagBatch.convertToList());
		publish(new TagBatchCreateEvent(result, lookupTable, OPERATION.CREATEBATCH));
		tagBatchLookupTableService.create(result);
		return result.stream().map(item -> item.getId()).collect(Collectors.toList());
	}

	@Override
	public Page<TagBatch> findTagBatches(Specification<TagBatch> spec, Pageable pageable) {
		return tagBatchDao.findAll(spec, pageable);
	}

	@Override
	public List<TagBatchPrintFormatVO> findTagBatchConfigs(Long eseId, int type) {
		if (!context.CURRECT_USER.getEseId().equals(1L) && !eseId.equals(context.CURRECT_USER.getEseId())) {
			throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest);
		}
		return Optional
				.ofNullable(
						tagBatchDao.findByEseIdAndTypeAndTagBatchConfigIdNot(eseId, TAG_BATCH_TYPE.fromValue(type), 0))
				.orElse(new ArrayList<>()).stream()
				.map(item -> new TagBatchPrintFormatVO(item.getName(), item.getTagBatchConfigId()))
				.collect(Collectors.toList());
	}

	@Override
	public void downloadFile(Long tagBatchId, HttpServletResponse response) {
		String md5 = "";
		TagBatch tagBatch = Optional.ofNullable(tagBatchDao.findOne(tagBatchId))
				.orElseThrow(() -> new RestException(HttpStatus.NOT_FOUND, CodeMessage.CanNotFindTagBatch, tagBatchId));
		if (!context.CURRECT_USER.getEseId().equals(1L)
				&& !tagBatch.getEseId().equals(context.CURRECT_USER.getEseId())) {
			throw new RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest);
		}
		if (tagBatch.getFileName() == null || tagBatch.getFileName().equals("")) {
			String fileName = String.join("/", context.CURRECT_USER.getEseId().toString(),
					DateFormatUtils.format(tagBatch.getCreateDate(), "yyyy/MM/dd"), tagBatchId.toString() + ".zip");
			tagBatch.setFileName(fileName);
		}
		Boolean result;
		try {
			result = fileService.ifExistingFile(cloudContainerConfig.getPrintFile(), tagBatch.getFileName());
			if (!result) {
				throw new RestException(HttpStatus.NOT_IMPLEMENTED, CodeMessage.CanNotFindPrintFile);
			}
		} catch (FileDatastoreException e) {
			throw new RestException(HttpStatus.NOT_IMPLEMENTED, CodeMessage.CanNotFindPrintFile);
		}
		 Path path=null;
		try {
			response.reset();
			String[] tagBatchNameList = tagBatch.getFileName().split("/");
			StringBuilder lastName = new StringBuilder();
			lastName.append(tagBatchNameList[tagBatchNameList.length - 2]).append("_")
					.append(tagBatchNameList[tagBatchNameList.length - 1]);
			response.setHeader("content-disposition",
					"attachment;filename=" + URLEncoder.encode(lastName.toString(), "UTF-8"));
			response.setHeader("Connection", "close");
			response.setHeader("Content-Type", "application/octet-stream");
			 OutputStream out = response.getOutputStream();
             path = fileService.downloadAsFile(cloudContainerConfig.getPrintFile(), tagBatch.getFileName(), tempBackFilePath+tagBatch.getFileName(), true);
            out.write(Files.readAllBytes(path));
            md5 = MD5Utils.generateFileMD5(path.toFile());
		} catch (Exception e) {
			e.printStackTrace();
		}
		publish(new TagBatchDownloadEvent(tagBatch, context.CURRECT_USER, context.ip, md5));
	}

	@Override
	public TagBatchPrintFileDto downloadTagBatchPrintFileByEseId(Long eseId, int downloadMethod) {
		// 找到最小没有被供应链下载过的标签批次
		TagBatch tagBatch = tagBatchDao.findTopByEseIdAndPrintFileStatusAndDownloadMethodOrderByIdAsc(eseId,
				PrintFileStatus.COMPLETE.getValue(), downloadMethod);
		if (tagBatch == null) {
			throw new RestException(HttpStatus.NOT_FOUND, CodeMessage.CanNotFindPrintFileByDownloadMethod,
					eseId.toString(), downloadMethod);
		}
		String fileUrl = null;
		try {
			fileUrl = fileService.getFileDownloadUrl(cloudContainerConfig.getPrintFile(), tagBatch.getFileName(),
					cloudContainerConfig.getPrintFileUrlExpiration());
		} catch (FileDatastoreException e) {
			throw new ServiceException(CodeMessage.GetFileUrlInCloudError, e, tagBatch.getFileName(),
					cloudContainerConfig.getPrintFile());
		}

		TagBatchPrintFileDto printFileDto = new TagBatchPrintFileDto();
		printFileDto.setEseId(tagBatch.getEseId());
		printFileDto.setTagBatchCount(tagBatch.getTagCount());
		printFileDto.setTagBatchId(tagBatch.getId());
		printFileDto.setTagBatchType(tagBatch.getType().getValue());
		printFileDto.setZipPassword(tagBatch.getZipPassword());
		if (StringUtils.isBlank(fileUrl)) {
			throw new RestException(HttpStatus.NOT_FOUND, CodeMessage.CanNotFindPrintFile, tagBatch.createFileName());
		}
		printFileDto.setFileUrl(fileUrl);

		// 更新批次下载文件状态
		tagBatch.setPrintFileStatus(PrintFileStatus.DOWNLOADED.getValue());
		tagBatchDao.save(tagBatch);// 乐观锁version冲突时，系统会抛异常出来
		return printFileDto;
	}

	@Override
	public TagMetaVO getTagMeta() {
		TagMetaVO tagMetaVO = new TagMetaVO();
		tagMetaVO.setTagBatchTypes(TagBatchType.values());
		tagMetaVO.setPrintfileFormatStatus(PrintFileFormatStatus.values());
		tagMetaVO.setProductionRegisers(ProductionRegister.values());
		return tagMetaVO;
	}

	@Override
	public List<TagBatchVO> buildTagBatchVO(List<TagBatchVO> tagBatchs) throws RestException {
		final List<Long> tagBatchIds = tagBatchs.stream().map(item -> item.getId()).collect(Collectors.toList());
		final Set<Long> eseIds = tagBatchs.stream().map(item -> item.getEseId()).collect(Collectors.toSet());
		List<EnterpriseDTO> enterpriseDtos = enterpriseClient.findByIds(eseIds);
		List<RangeActivation> rangeActivations = rangeActivationDao.findByTagBatchIdIn(tagBatchIds);

		TagBatchStatusRequest tagbatchRequest = new TagBatchStatusRequest();
		List<TagBatchSequenceInfo> tagBatchSequenceInfos = new ArrayList<>();
		tagBatchIds.stream().forEach(id -> {
			rangeActivations.stream().filter(range -> range.getTagBatchId().equals(id)).forEach(item -> {
				TagBatchSequenceInfo tagBatchSequenceInfo = new TagBatchSequenceInfo();
				tagBatchSequenceInfo.setTagBatchId(id);
				tagBatchSequenceInfo.setSeqNumStart(item.getSeqnumStart());
				tagBatchSequenceInfo.setSeqNumEnd(item.getSeqnumEnd());
				tagBatchSequenceInfos.add(tagBatchSequenceInfo);
			});
		});
		tagbatchRequest.setStatus(TagStatus.ACTIVATE.getStatus());
		tagbatchRequest.setTagBatchList(tagBatchSequenceInfos);
		TagBatchStatusResponse tagBatchResponse = tagBatchReportClient.tagBatchStatusCount(tagbatchRequest);

		tagBatchs.stream().forEach(item -> {
			item.setActiveCount(0);
			setRegisterStatus(tagBatchResponse, item,
					rangeActivations.stream()
							.filter(range -> range.getTagBatchId().longValue() == item.getId().longValue())
							.collect(Collectors.toList()));
			EnterpriseDTO enterpriseDto = enterpriseDtos.stream().filter(ent -> item.getEseId() == ent.getId())
					.findFirst().orElse(new EnterpriseDTO());
			item.setEseName(enterpriseDto.getName());
		});
		setDownloadCount(tagBatchs);
		setPrintParam(tagBatchs);
		return tagBatchs;
	}

	private void setDownloadCount(List<TagBatchVO> tagBatchs) {
		tagBatchs.stream().forEach(item -> {
			item.setDownloadCount(tagBatchDownloadLogDao.countBytagBatchId(item.getId()));
		});
	}

	private void setPrintParam(List<TagBatchVO> tagBatchs) {
		List<Long> ids = tagBatchs.stream().filter(item -> item.getTagBatchConfigId() != null)
				.map(item -> item.getTagBatchConfigId()).collect(Collectors.toList());
		List<TagBatchConfig> configs = tagBatchConfigDao.findByIdIn(ids);
		List<IndustrialComputerDTO> industrialComputerDTOS = industrialComputerClient
				.findByIds(configs.stream().map(item -> item.getTerminalId()).collect(Collectors.toSet()));
		List<FactoryDTO> factoryDTOS = factoryClient
				.findByIds(configs.stream().map(item -> item.getPrintFactoryId()).collect(Collectors.toSet()));
		tagBatchs.stream().forEach(tagbatch -> {
			if (tagbatch.getTagBatchConfigId() != null && tagbatch.getTagBatchConfigId() != 0) {
				try {
					Optional<TagBatchConfig> tmpConfig = configs.stream()
							.filter(item -> item.getId().equals(tagbatch.getTagBatchConfigId())).findFirst();
					if (!tmpConfig.isPresent())
						return;
					Optional<FactoryDTO> tmpFactory = factoryDTOS.stream()
							.filter(factory -> factory.getId().equals(tmpConfig.get().getPrintFactoryId())).findFirst();
					if (tmpFactory.isPresent())
						tagbatch.setPrintFactory(tmpFactory.get().getName());
					Optional<IndustrialComputerDTO> tmpIndustrialComputerDTO = industrialComputerDTOS.stream()
							.filter(device -> device.getId().equals(tmpConfig.get().getTerminalId())).findFirst();
					if (tmpIndustrialComputerDTO.isPresent())
						tagbatch.setPrintDevice(tmpIndustrialComputerDTO.get().getName());
				} catch (Exception e) {
				}
			}
		});
	}

	@Override
	public Long CodeCount(long eseId) {
		if (CommonConstants.SYSTEM_INNER_ESEID.equals(eseId)) {
			return tagBatchDao.sumCode();
		} else {
			return Optional.ofNullable(tagBatchDao.sumTagCountByEseId(eseId)).orElse(0L);
		}
	}

	/**
	 * 设置生成登记状态
	 */
	private void setRegisterStatus(TagBatchStatusResponse tagBatchResponse, TagBatchVO tagBatch,
								   List<RangeActivation> rangeActivations) {
		List<RangeActivationVO> batchRanges = rangeActivations.stream()
				.map(range -> mapToRangeActivationVO(tagBatchResponse, tagBatch, range)).collect(Collectors.toList());
		tagBatch.setRangeActivationVOs(batchRanges);
		if (tagBatch.getType().intValue() == TagBatchType.ROLL.getValue().intValue()) {
			return;
		}
		if (rangeActivations.size() == 0) {
			tagBatch.setRegister(ProductionRegister.TODO.getValue());
			return;
		}
		if (rangeActivations.stream().mapToLong(item -> item.getSeqnumEnd() - item.getSeqnumStart() + 1)
				.sum() < (Long.valueOf(tagBatch.getSeqnumEnd()) - Long.valueOf(tagBatch.getSeqnumStart()) + 1)) {
			tagBatch.setRegister(ProductionRegister.MODIFIED.getValue());
		} else {
			tagBatch.setRegister(ProductionRegister.IMMUTABLE.getValue());
		}
	}

	private RangeActivationVO mapToRangeActivationVO(TagBatchStatusResponse tagBatchResponse, TagBatchVO tagBatch,
													 RangeActivation rangeActivation) {
		RangeActivationVO vo = new RangeActivationVO();
		try {
			vo.setId(rangeActivation.getId());
			vo.setSeqnumEnd(rangeActivation.getSeqnumEnd() + "");
			vo.setSeqnumStart(rangeActivation.getSeqnumStart() + "");
			vo.setCreated(rangeActivation.getCreateDate());
			vo.setTagBatch(tagBatch.getId());
			vo.setTagBatchName(tagBatch.getName());
			vo.setCreated(rangeActivation.getCreateDate());
			vo.setProductId(rangeActivation.getProductId());
			vo.setFactoryId(rangeActivation.getFactoryId());
			vo.setFranchiserId(rangeActivation.getFranchiserId());
			vo.setActivationMethod(rangeActivation.getActivationMethod());
			vo.setActivationParam(rangeActivation.getActivationParam());
			if (rangeActivation.getActivationMethod().intValue() == ActivationMethod.Custom.getValue().intValue()) {
				vo.setActivationParam(rangeActivation.getActivationParam());
			}
			vo.setActiveCount(getRangeActiveCount(rangeActivation.getSeqnumStart(), tagBatchResponse));
			vo.setStatus(rangeActivation.getStatus());
//			// 激活状态为不可修改
//			vo.setStatus(ProductionRegister.MODIFIED.getValue());
//			if (rangeActivation.getStatus().intValue() == TagRangeStatus.ACTIVATED.getValue().intValue()) {
//				vo.setStatus(ProductionRegister.IMMUTABLE.getValue());
//			}
		} catch (Exception ex) {
		}

		return vo;
	}

	private Long getRangeActiveCount(Long startNum, TagBatchStatusResponse tagBatchResponse) {
		TagBatchSequenceInfo tagBatchSequenceInfo = tagBatchResponse.getTagBatchList().stream()
				.filter(item -> item.getSeqNumStart().equals(startNum)).findFirst().orElse(new TagBatchSequenceInfo());
		return tagBatchSequenceInfo.getCount() == null ? 0 : tagBatchSequenceInfo.getCount();
	}

	@Override
	public String getFileNameByTagBatchId(Long tagBatchId) {
		StringBuilder result = new StringBuilder();
		TagBatch tagBatch = tagBatchDao.findOne(tagBatchId);
		TagBatchConfig res = tagBatchConfigDao.findOne(tagBatchId);

		FactoryDTO factory = factoryClient.findById(res.getPrintFactoryId());
		industrialComputerClient.findById(res.getTerminalId());
		// productClient.findById(res.get);
		if (factory != null) {
			result.append(factory.getCode() + "-");
			result.append(factory.getCode() + "-");
		}
		result.append(factory.getCode() + "-");
		result.append(tagBatchId);
		return result.toString();
	}
	/*
	 * @Override public String downloadTagBatchPrintFile(Long tagBatchId) {
	 * TagBatch tagBatch =
	 * Optional.ofNullable(tagBatchDao.findOne(tagBatchId)).orElseThrow(() ->
	 * new RestException(HttpStatus.NOT_FOUND, CodeMessage.CanNotFindTagBatch,
	 * tagBatchId)); if (!context.CURRECT_USER.getEseId().equals(1L) &&
	 * !tagBatch.getEseId().equals(context.CURRECT_USER.getEseId())) { throw new
	 * RestException(HttpStatus.BAD_REQUEST, CodeMessage.InvalidRequest); }
	 * String fileUrl = null; if (tagBatch.getFileName() != null &&
	 * !tagBatch.getFileName().equals(0L)) { try { fileUrl =
	 * fileService.getFileDownloadUrl(cloudContainerConfig.getPrintFile(),
	 * tagBatch.getFileName(),
	 * cloudContainerConfig.getPrintFileUrlExpiration()); } catch
	 * (FileDatastoreException e) { throw new
	 * ServiceException(CodeMessage.GetFileUrlInCloudError, e,
	 * tagBatch.getFileName(), cloudContainerConfig.getPrintFile()); } if
	 * (StringUtils.isBlank(fileUrl)) { throw new
	 * RestException(HttpStatus.NOT_FOUND, CodeMessage.CanNotFindPrintFile,
	 * tagBatch.createFileName()); } } return fileUrl; }
	 */

	@Override
	public List<TagBatchVO> findTagBatchesBytagBatchIdOrName(Specification<TagBatch> spec) {
		List<TagBatch> TagBatch = tagBatchDao.findAll(spec);
		List<TagBatchVO> TagBatchVOList = Mapper.mapList(TagBatch, TagBatchVO.class);
		final List<Long> tagBatchIds = TagBatchVOList.stream().map(item -> item.getId()).collect(Collectors.toList());
		List<RangeActivation> rangeActivations = rangeActivationDao.findByTagBatchIdIn(tagBatchIds);
		// TagBatchStatusRequest tagbatchRequest = new TagBatchStatusRequest();
		// List<TagBatchSequenceInfo> tagBatchSequenceInfos = new ArrayList<>();
		TagBatchVOList.stream().forEach(tagBatchVO -> {
			Optional<TagScrap> tagScrapTagBatch = Optional.ofNullable(tagScrapDao.findByTagBatchId(tagBatchVO.getId()));
			if (tagScrapTagBatch.isPresent()) {
				tagBatchVO.setScrapStatus(1);
			}
			List<RangeActivation> rangeActivation = rangeActivations.stream()
					.filter(range -> range.getTagBatchId().equals(tagBatchVO.getId())).collect(Collectors.toList());
			List<RangeActivationVO> rangeActivationVOs = Mapper.mapList(rangeActivation, RangeActivationVO.class);
			rangeActivationVOs.stream().forEach(res -> {
				Optional<TagScrap> tagScrap = Optional.ofNullable(tagScrapDao.findByRangeId(res.getId()));
				if (tagScrap.isPresent()) {
					res.setScrapStatus(1);
				}
			});
			tagBatchVO.setRangeActivationVOs(rangeActivationVOs);
		});
		// tagbatchRequest.setTagBatchList(tagBatchSequenceInfos);
		return TagBatchVOList;
	}

	@Override
	public List<TagAvailableTypeDto> getAvailableTypeByTerminalId(Long terminalId, Long eseId) {
		logger.info("工控机ID:"+terminalId+"企业ID:"+eseId);
		List<TagAvailableTypeDto> result = new ArrayList<>();
		List<TagBatchConfig> tagBatchConfigList = tagBatchConfigDao.findByTerminalIdAndDownloadMethod(terminalId,
				PrintFileDownloadMethod.OnLine.getValue());
		if (tagBatchConfigList.size() > 0) {
			List<Long> ids = tagBatchConfigList.stream().filter(item -> item.getTagBatchId() != null)
					.map(item -> item.getTagBatchId()).collect(Collectors.toList());
			List<TagBatchLookupTable> tagBatchLookupTables = tagBatchLookupTableDao.findByEseIdAndTagBatchIdIn(eseId,
					ids);
			List<Long> tagBatchIds = tagBatchLookupTables.stream()
					.filter(tagBatchLookupTable -> (tagBatchLookupTable.getSeqnumEnd()
							- tagBatchLookupTable.getSeqnumStart() - tagBatchLookupTable.getCurrentCount() + 1) > 0)
					.map(item -> item.getTagBatchId()).collect(Collectors.toList());
			List<TagBatch> tagBatchs = tagBatchDao.findByIdIn(tagBatchIds);
			Set<TAG_BATCH_TYPE> res = tagBatchs.stream().map(item -> item.getType()).collect(Collectors.toSet());
			for (TAG_BATCH_TYPE tag_BATCH_TYPE : res) {
				TagAvailableTypeDto tagAvailableTypeDto = new TagAvailableTypeDto();
				tagAvailableTypeDto.setTagType(tag_BATCH_TYPE.getValue());
				tagAvailableTypeDto.setTagTypeName(tag_BATCH_TYPE.getName());
				result.add(tagAvailableTypeDto);
			}
		}
		return result;
	}

	@Override
	@Transactional
	public TerminalDownloadResponse downloadByTerminal(TerminalDownloadRequest terminalDownloadRequest, Long terminalId,
													   Long eseId) throws Exception {
		logger.info("工控机ID:"+terminalId+"企业ID:"+eseId);
		Integer downloadNum = terminalDownloadRequest.getDownloadNum();
		List<Map> resultData = new ArrayList<>();
		StringBuilder rangeIds = new StringBuilder();
		TerminalDownloadRecord terminalDownloadRecord = new TerminalDownloadRecord();
		TerminalDownloadResponse terminalDownloadResponse = new TerminalDownloadResponse();
		List<TagBatchConfig> tagBatchConfigList = tagBatchConfigDao.findByTerminalIdAndDownloadMethod(terminalId,
				PrintFileDownloadMethod.OnLine.getValue());
		if (tagBatchConfigList.size() > 0) {
			List<Long> ids = tagBatchConfigList.stream().filter(item -> item.getTagBatchId() != null)
					.map(item -> item.getTagBatchId()).collect(Collectors.toList());
			List<TagBatchLookupTable> tagBatchLookupTables = tagBatchLookupTableDao.findByEseIdAndTagBatchIdIn(eseId,
					ids);
			List<Long> tagBatchIds = tagBatchLookupTables.stream()
					.filter(tagBatchLookupTable -> (tagBatchLookupTable.getSeqnumEnd()
							- tagBatchLookupTable.getSeqnumStart() - tagBatchLookupTable.getCurrentCount() + 1) > 0)
					.map(item -> item.getTagBatchId()).collect(Collectors.toList());
			List<TagBatch> tagBatchs = tagBatchDao
					.findByTypeAndIdIn(TAG_BATCH_TYPE.fromValue(terminalDownloadRequest.getTagType()), tagBatchIds);
			if (tagBatchs.isEmpty()) {
				terminalDownloadResponse.setCurrentId(0L);
				terminalDownloadResponse.setResultMsg("无可用码");
				return terminalDownloadResponse;
			}
			for (TagBatch tagBatch : tagBatchs) {
				TagBatchLookupTable tagBatchLookupTable = tagBatchLookupTableDao.findByTagBatchId(tagBatch.getId());
				Integer surplusSeq = (int) (tagBatchLookupTable.getSeqnumEnd() - tagBatchLookupTable.getSeqnumStart()
						- tagBatchLookupTable.getCurrentCount() + 1);
				if (surplusSeq - downloadNum >= 0) {
					downloading(resultData, tagBatch, tagBatchLookupTable.getCurrentCount().intValue(), downloadNum);
					tagBatchLookupTable.setCurrentCount(tagBatchLookupTable.getCurrentCount() + downloadNum);
					tagBatchLookupTableDao.save(tagBatchLookupTable);
					RangeActivation rangeActivation = new RangeActivation();
					rangeActivation.setTagBatchId(tagBatch.getId());
					rangeActivation.setSeqnumEnd(tagBatchLookupTable.getSeqnumStart()
							+ tagBatchLookupTable.getCurrentCount() + downloadNum - 1);
					rangeActivation.setSeqnumStart(
							tagBatchLookupTable.getSeqnumStart() + tagBatchLookupTable.getCurrentCount() + 1);
					RangeActivation rangeActivation1 = rangeActivationDao.save(rangeActivation);
					rangeIds.append(rangeActivation1.getId() + ",");
					break;
				} else {
					downloadNum -= surplusSeq;
					downloading(resultData, tagBatch, tagBatchLookupTable.getCurrentCount().intValue(), surplusSeq);
					tagBatchLookupTable.setCurrentCount(tagBatchLookupTable.getCurrentCount() + surplusSeq);
					tagBatchLookupTableDao.save(tagBatchLookupTable);
					RangeActivation rangeActivation = new RangeActivation();
					rangeActivation.setTagBatchId(tagBatch.getId());
					rangeActivation.setSeqnumStart(
							tagBatchLookupTable.getSeqnumStart() + tagBatchLookupTable.getCurrentCount() + 1);
					rangeActivation.setSeqnumEnd(
							rangeActivation.getSeqnumStart() + tagBatchLookupTable.getCurrentCount() + surplusSeq - 1);
					RangeActivation rangeActivation1 = rangeActivationDao.save(rangeActivation);
					rangeIds.append(rangeActivation1.getId() + ",");
				}
			}
			terminalDownloadResponse.setResultData(resultData);
			terminalDownloadResponse.setResultMsg("处理结束");
			terminalDownloadRecord.setRangeIds(rangeIds.toString());
			terminalDownloadRecord.setTerminalId(terminalId);
			terminalDownloadRecord.setTagDownloadCount(terminalDownloadRequest.getDownloadNum()-downloadNum);
			terminalDownloadRecord.setTagType(terminalDownloadRequest.getTagType());
			terminalDownloadRecord.setEseId(eseId);
			Optional<IndustrialComputerDTO> industrial = Optional
					.ofNullable(industrialComputerClient.findById(terminalId));
			if (industrial.isPresent()) {
				terminalDownloadRecord.setPrintFactoryId(industrial.get().getFactoryId());
			}
			TerminalDownloadRecord terminalDownloadResult = terminalDownloadResultDao.save(terminalDownloadRecord);
			terminalDownloadResponse.setCurrentId(terminalDownloadResult.getId());
		}
		return terminalDownloadResponse;
	}

	private void downloading(List<Map> resultData, TagBatch tagBatch, Integer currentCount, Integer downloadNum)
			throws Exception {
		Path localBackPath = null;
		TagBatchConfig tagBatchConfig = tagBatchConfigDao.findByTagBatchId(tagBatch.getId());
		List<String> res = jsonMapper.fromCollectionJson(tagBatchConfig.getFieldsConfig(), String.class);
		logger.info("获取解压文件路径");
		localBackPath = getPrintFilePath(tagBatch, tagBatchConfig);
		if (localBackPath == null) {
			throw new RestException(HttpStatus.NOT_FOUND, CodeMessage.CanNotFindPrintFile, tagBatch.getName());
		}
		RandomAccessFile accessFile = new RandomAccessFile(localBackPath.toFile(), "r");
		long lineLen = accessFile.length() / tagBatch.getTagCount();// 每行长度
		for (int i = 0; i < downloadNum; i++) {
			accessFile.seek((currentCount + i) * lineLen);// 跳到某个位置(指针位置)
			String tagsLine = accessFile.readLine();
			String[] strList = null;
			switch (tagBatch.getType()) {
				case NORMAL:
				case ROLL:
				case WRAP:
					strList = res.stream().findFirst().get().split("\\|");
					break;
				case PACKAGE:
				case DUPLICATE:
					for (String resPack : res) {
						strList = resPack.split("\\|");
					}
					break;
				default:
					break;
			}
			String[] res1 = tagsLine.split(",");
			Map< String, String> result=new HashMap<>();
			for (int j = 0; j < res1.length; j++) {
				result.put(strList[j],  res1[j]);
			}
			resultData.add(result);
		}

	}

	private Path getPrintFilePath(TagBatch tagBatch, TagBatchConfig tagBatchConfig) throws Exception {
		String[] tagBatchNameList = tagBatch.getFileName().split("/");
		StringBuilder lastName = new StringBuilder();
		lastName.append(tagBatchNameList[tagBatchNameList.length - 2]).append("_")
				.append(tagBatchNameList[tagBatchNameList.length - 1]);
		String localPath = tempBackFilePath + "printFile" + File.separator + tagBatch.getId() + File.separator;
		String localFirstUnzipPath = localPath + "firstUnzip" + File.separator;
		Path lastPath = Paths.get(localFirstUnzipPath + tagBatch.getName() + "." + tagBatchConfig.getFileType());
		if (!Files.exists(lastPath)) {
			Path tempPath = Paths.get(localFirstUnzipPath);
			if (!Files.exists(tempPath)) {
				Files.createDirectories(tempPath);
			}
			fileService.downFileToLocal(cloudContainerConfig.getPrintFile(), tagBatch.getFileName(),
					localPath + lastName, false);
			CipherZipUtil.unzip(localPath + lastName, localFirstUnzipPath, tagBatch.getZipPassword());
			Files.delete(Paths.get(localPath + lastName));// 删除zip源文件
		}
		return lastPath;// 指向解压后的txt文件

	}

	@Override
	public TagBatch find(Long tagBatchId) {
		return tagBatchDao.findOne(tagBatchId);
	}

	@Override
	public void updateTerminalDownload(Long successID) throws Exception {
		logger.info("下載成功记录ID:"+successID);
		Optional<TerminalDownloadRecord> updateStatus = Optional
				.ofNullable(terminalDownloadResultDao.findOne(successID));
		if (updateStatus.isPresent()) {
			updateStatus.get().setTagDownloadStatus(true);
			terminalDownloadResultDao.save(updateStatus.get());
			logger.info("记录状态更新成功");
		}
	}

	@Override
	public AvailableNum getAvailableNum(String terminalId,Integer tagType,Long eseId) {
		logger.info("工控机ID:"+terminalId+"企业ID:"+eseId);
		AvailableNum result=new AvailableNum();
		List<TagBatchConfig> tagBatchConfigList = tagBatchConfigDao.findByTerminalIdAndDownloadMethod(Long.parseLong(terminalId),
				PrintFileDownloadMethod.OnLine.getValue());
		if (tagBatchConfigList.size() > 0) {
			AtomicLong  res=new AtomicLong();
			List<Long> ids = tagBatchConfigList.stream().filter(item -> item.getTagBatchId() != null)
					.map(item -> item.getTagBatchId()).collect(Collectors.toList());
			List<TagBatch> tagBatchs = tagBatchDao.findByTypeAndIdIn(TAG_BATCH_TYPE.fromValue(tagType), ids);
			List<Long> tagBatchIds=tagBatchs.stream().filter(item -> item.getId()!= null)
					.map(item ->  item.getId()).collect(Collectors.toList());
			List<TagBatchLookupTable> tagBatchLookupTables = tagBatchLookupTableDao.findByEseIdAndTagBatchIdIn(eseId,tagBatchIds);
			tagBatchLookupTables.stream()
					.filter(tagBatchLookupTable -> (tagBatchLookupTable.getSeqnumEnd()
							- tagBatchLookupTable.getSeqnumStart() - tagBatchLookupTable.getCurrentCount() + 1) > 0).forEach(tagBatchLookupTable->{res.addAndGet((tagBatchLookupTable.getSeqnumEnd()
					- tagBatchLookupTable.getSeqnumStart() - tagBatchLookupTable.getCurrentCount() + 1));});
			result.setAvailableNum(res.get());
		}
		return result;
	}

}
